package com.pai4j.pgc.service.community;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.pai4j.common.bean.PAIPageResponseBeanUtil;
import com.pai4j.common.enums.RedisKeyEnum;
import com.pai4j.common.enums.community.QuestionRecommendReasonEnum;
import com.pai4j.common.enums.community.ResourceBehaviorTypeEnum;
import com.pai4j.common.enums.community.ResourceTypeEnum;
import com.pai4j.common.util.DateUtils;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.common.util.ListUtil;
import com.pai4j.common.util.RedisUtil;
import com.pai4j.domain.community.vo.response.BannerImageResponseVO;
import com.pai4j.domain.community.vo.response.LinkAdvResponseVO;
import com.pai4j.domain.community.vo.response.cc.*;
import com.pai4j.domain.community.vo.response.resource.ResourceBaseResponseVO;
import com.pai4j.domain.vo.response.UserBaseResponseInfoVO;
import com.pai4j.pgc.dao.community.ICCNavDAO;
import com.pai4j.pgc.dao.community.ICCPathDAO;
import com.pai4j.pgc.dao.community.ICCQuestionDAO;
import com.pai4j.pgc.dao.community.ICCVideoDAO;
import com.pai4j.pgc.entity.community.CCNavEntity;
import com.pai4j.pgc.entity.community.CCPathEntity;
import com.pai4j.pgc.entity.community.CCQuestionEntity;
import com.pai4j.pgc.entity.community.CCVideoEntity;
import com.pai4j.pgc.pojo.CTCHomeRecommendQuestionVO;
import com.pai4j.pgc.pojo.CTCHomeRecommendVideoVO;
import com.pai4j.pgc.service.behavior.AbstractResourceBehaviorService;
import com.pai4j.pgc.service.behavior.ResourceBehaviorFactory;
import com.pai4j.pgc.service.resource.ResourceListService;
import com.pai4j.remote.user.UserServiceClient;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 *  技术社区推荐专栏
 *
 * @author: CYM-pai
 * @date: 2025/10/27 14:07
 **/
@Service
public class CTCScheduleService {

    @Autowired
    private CCPathService pathService;
    @Autowired
    private CCQuestionService questionService;
    @Autowired
    private CCVideoService videoService;
    @Autowired
    private CCExperienceService experienceService;
    @Autowired
    private ResourceListService resourceListService;
    @Autowired
    private ICCPathDAO pathDAO;
    @Autowired
    private ICCQuestionDAO questionDAO;
    @Autowired
    private ICCVideoDAO videoDAO;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CCOpenSourceService openSourceService;
    @Autowired
    private ICCNavDAO navDAO;
    @Autowired
    private UserServiceClient userServiceClient;
    @Autowired
    private CCVideoSummaryService videoSummaryService;

    /**
     * 刷新栏目首页热点数据
     */
    public void refreshCTCHomeHotData() {
        // 查询全部栏目
        List<Long> pathIdList = Lists.newArrayList(28L);
        /**
         * 刷新社区公告数据
         */
        this.refreshCTCHomeHotData(pathIdList);
    }

    private void refreshCTCHomeHotData(List<Long> pathIdList) {
        for (Long pathId : pathIdList) {
            // 1. 刷新栏目基础信息缓存缓存
            pathService.refreshCTCPathDetailCacheByPathId(pathId);
            // 3. 刷新栏目首页问答数据缓存
            this.refreshCTCHomeQuestionList(pathId);
            this.refreshCTCHomeVideoList(pathId);
            // 4. 刷新栏目首页热门资源数据缓存
            this.refreshCTCHomeResource(pathId);
            // 5. 刷新栏目首页推荐经验缓存
            this.refreshCTCHomeExperience(pathId);
            // 6. 刷新首页开源项目推荐列表
            this.refreshCTCHomeOpenSource(pathId);
            // 7. 刷新置顶导航
            this.refreshCTCHomeNavList(pathId);
            // 8. 刷新社区热门标签
            this.refreshCCPathHotExperienceSignsCache(pathId);
        }
    }

    public List<UserBaseResponseInfoVO> getCTCActivityUserFromCache(int size) {
        String key = RedisKeyEnum.CTC_PATH_ACTIVITY_USER_CACHE.getKey();
        Set<String> userIdCache = redisUtil.zreverseRange(key, 0, size);
        if (CollectionUtils.isEmpty(userIdCache)) {
            return Collections.emptyList();
        }
        return userServiceClient.batchGetUserListInfoFromCache(new ArrayList<String>(userIdCache));
    }

    public List<CTCPathBaseVO> getCTCActivityPathFromCache(int size) {
        String key = RedisKeyEnum.CTC_PATH_ACTIVITY_PATH_CACHE.getKey();
        Set<String> pathIdCache = redisUtil.zreverseRange(key, 0, size);
        if (CollectionUtils.isEmpty(pathIdCache)) {
            return Collections.emptyList();
        }
        List<Long> pathIdList = pathIdCache.stream().map(Long::valueOf).collect(Collectors.toList());
        return pathService.batchGetPathBaseListFromCache(pathIdList);
    }

    public void addCTCActivityUserCache(String userId) {
        if (StringUtils.isBlank(userId)) {
            return;
        }
        String key = RedisKeyEnum.CTC_PATH_ACTIVITY_USER_CACHE.getKey();
        redisUtil.zadd(key, userId, DateUtils.getCurrentTimeMillis(), RedisKeyEnum.CTC_PATH_ACTIVITY_USER_CACHE.getExpireTime());
    }

    public void addCTCActivityPathCache(Long pathId) {
        if (pathId == null) {
            return;
        }
        String key = RedisKeyEnum.CTC_PATH_ACTIVITY_PATH_CACHE.getKey();
        redisUtil.zadd(key, pathId.toString(), DateUtils.getCurrentTimeMillis(), RedisKeyEnum.CTC_PATH_ACTIVITY_PATH_CACHE.getExpireTime());
    }


    private String buildCTCBannerImageCode(Long pathId) {
        return "CTC_".concat(pathId.toString());
    }


    private void refreshCCPathHotExperienceSignsCache(Long pathId) {
        experienceService.refreshCCPathHotExperienceSignsCache(pathId);
    }

    /**
     * 查询全部栏目ID集
     *
     * @return
     */
    private List<Long> getAllPathIdFromDB() {
        List<CCPathEntity> pathEntities = pathDAO.findAllBySubscribePaths();
        return pathEntities.stream().map(CCPathEntity::getId).collect(Collectors.toList());
    }

    public List<CTCHomeRecommendQuestionVO> getHomeQuestionFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_QUESTIONS_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        List<CTCHomeRecommendQuestionVO> questionVOList =
                JsonUtil.fromJson(cache, new TypeReference<List<CTCHomeRecommendQuestionVO>>() {});
        if (CollectionUtils.isEmpty(questionVOList)) {
            return questionVOList;
        }
        List<String> authors = questionVOList.stream().map(CTCHomeRecommendQuestionVO::getAuthor).collect(Collectors.toList());
        Map<String, UserBaseResponseInfoVO> authorMap = userServiceClient.batchGetUserInfoFromCache(authors);
        questionVOList.forEach(q -> {
            q.setAuthorUser(authorMap.get(q.getAuthor()));
        });
        return questionVOList;
    }

    public List<CTCHomeRecommendVideoVO> getHomeVideoFromCache(Long pathId, Integer size) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_VIDEOS_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        List<CTCHomeRecommendVideoVO> videoBaseVOList =
                JsonUtil.fromJson(cache, new TypeReference<List<CTCHomeRecommendVideoVO>>() {});
        if (CollectionUtils.isEmpty(videoBaseVOList)) {
            return videoBaseVOList;
        }
        List<String> authors = videoBaseVOList.stream().map(CTCHomeRecommendVideoVO::getAuthor).collect(Collectors.toList());
        Map<String, UserBaseResponseInfoVO> authorMap = userServiceClient.batchGetUserInfoFromCache(authors);
        videoBaseVOList.forEach(q -> {
            q.setAuthorUser(authorMap.get(q.getAuthor()));
        });
        ListUtil.shuffle(videoBaseVOList);
        size = Math.min(size, videoBaseVOList.size());
        return videoBaseVOList.subList(0, size);
    }

    public List<CTCHomeRecommendVideoVO> videoList(Long pathId, String userId) {
        AbstractResourceBehaviorService attendService =
                ResourceBehaviorFactory.getBehaviorService(ResourceBehaviorTypeEnum.FOCUS.getBehavior());
        Map<Long, Boolean> isAttendMap = attendService.getIsBehaviorFromCache(ResourceTypeEnum.CTC_PATH.getType(), Arrays.asList(pathId), userId);
        boolean isSub = isAttendMap.getOrDefault(pathId, false);
        String key = RedisKeyEnum.CTC_VIDEO_NEW_ZSET_CACHE.getKey(pathId.toString());
        if (!redisUtil.exists(key)) {
            videoService.initCTCNewQuestionCache(pathId);
        }
        Set<String> videoIdSet = redisUtil.zrange(key, 0, Integer.MAX_VALUE);
        List<Long> qidList = videoIdSet.stream().map(Long::valueOf).collect(Collectors.toList());
        List<CTCVideoBaseVO> videoBaseVOList = videoService.batchGetQuestionListFromCache(qidList);
        Map<Long, Long> viewCountMap = videoService.batchGetQuestionViewCount(qidList);
        Map<Long, Boolean> summaryStatusMap = videoSummaryService.hasSummary(qidList);
        List<CTCHomeRecommendVideoVO> list = new ArrayList<>();
        for (CTCVideoBaseVO videoBaseVO : videoBaseVOList) {
            CTCHomeRecommendVideoVO video = new CTCHomeRecommendVideoVO();
            video.setId(videoBaseVO.getId());
            video.setTitle(videoBaseVO.getTitle());
            video.setCover(videoBaseVO.getCover());
            video.setCreateTime(videoBaseVO.getCreateTime());
            video.setViewCount(viewCountMap.getOrDefault(videoBaseVO.getId(), 0L));
            if (isSub) {
                video.setVideo(videoBaseVO.getVideo());
            }
            video.setHasSummary(summaryStatusMap.getOrDefault(video.getId(), false));
            list.add(video);
        }
        return list;
    }

    public List<BannerImageResponseVO> getHomeBannerFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_BANNER_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        return JsonUtil.fromJson(cache, new TypeReference<List<BannerImageResponseVO>>() {});
    }
    
    
    public List<LinkAdvResponseVO> getCtcNoticeFromCache() {
        String key = RedisKeyEnum.CTC_HOME_NOTICE_CACHE.getKey();
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        return JsonUtil.fromJson(cache, new TypeReference<List<LinkAdvResponseVO>>() {});
    }
    
    public List<CTCExperienceListVO> getHomeExperienceFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_EXPERIENCE_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        List<CTCExperienceListVO> experienceListVOList =
                JsonUtil.fromJson(cache, new TypeReference<List<CTCExperienceListVO>>() {});
        if (CollectionUtils.isEmpty(experienceListVOList)) {
            return experienceListVOList;
        }
        List<String> authors = experienceListVOList.stream().map(CTCExperienceListVO::getExperience)
                .map(CTCExperienceBaseVO::getAuthor).collect(Collectors.toList());
        Map<String, UserBaseResponseInfoVO> authorMap = userServiceClient.batchGetUserInfoFromCache(authors);
        experienceListVOList.forEach(exp -> {
            exp.setAuthor(authorMap.get(exp.getExperience().getAuthor()));
        });
        return experienceListVOList;
    }
    
    public List<ResourceBaseResponseVO> getHomeResourceFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_RESOURCE_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        return JsonUtil.fromJson(cache, new TypeReference<List<ResourceBaseResponseVO>>() {});
    }
    
    public List<CCOpenSourceDetailVO> getHomeOpenSourceFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_OPEN_SOURCE_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        return JsonUtil.fromJson(cache, new TypeReference<List<CCOpenSourceDetailVO>>() {});
    }
    public List<CCNavVO> getHomeNavListFromCache(Long pathId) {
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_NAV_CACHE.getKey(pathId.toString());
        String cache = redisUtil.get(key);
        if (StringUtils.isBlank(cache)) {
            return Collections.emptyList();
        }
        return JsonUtil.fromJson(cache, new TypeReference<List<CCNavVO>>() {});
    }

    private void refreshCTCHomeExperience(Long pathId) {
        PAIPageResponseBeanUtil<CTCExperienceListVO> experienceListPage = experienceService.recommendPageList(pathId, 1, 10, null);
        List<CTCExperienceListVO> experienceListVOList = experienceListPage.getData();
        if (experienceListVOList == null) {
            experienceListVOList = new ArrayList<>();
        }
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_EXPERIENCE_CACHE.getKey(pathId.toString());
        redisUtil.set(key, JsonUtil.toJsonString(experienceListVOList), RedisKeyEnum.CTC_HOME_RECOMMEND_EXPERIENCE_CACHE.getExpireTime());
    }

    private void refreshCTCHomeOpenSource(Long pathId) {
        List<CCOpenSourceDetailVO> osList = openSourceService.recommendList(pathId, 4);
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_OPEN_SOURCE_CACHE.getKey(pathId.toString());
        redisUtil.set(key, JsonUtil.toJsonString(osList), RedisKeyEnum.CTC_HOME_RECOMMEND_OPEN_SOURCE_CACHE.getExpireTime());
    }

    private void refreshCTCHomeNavList(Long pathId) {
        List<CCNavEntity> navEntities = navDAO.queryCTCRecommendNavList(pathId, 6);
        List<CCNavVO> navList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(navEntities)) {
            navList = navEntities.stream().map(nav -> {
                CCNavVO navVO = new CCNavVO();
                navVO.setUrl(nav.getUrl());
                navVO.setName(nav.getName());
                return navVO;
            }).collect(Collectors.toList());
        }
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_NAV_CACHE.getKey(pathId.toString());
        redisUtil.set(key, JsonUtil.toJsonString(navList), RedisKeyEnum.CTC_HOME_RECOMMEND_NAV_CACHE.getExpireTime());
    }

    private void refreshCTCHomeResource(Long pathId) {
        List<ResourceBaseResponseVO> resourceBaseResponseVOList = resourceListService.getCTCHomeResource(pathId, 6);
        if (resourceBaseResponseVOList == null) {
            resourceBaseResponseVOList = new ArrayList<>();
        }
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_RESOURCE_CACHE.getKey(pathId.toString());
        redisUtil.set(key, JsonUtil.toJsonString(resourceBaseResponseVOList), RedisKeyEnum.CTC_HOME_RECOMMEND_RESOURCE_CACHE.getExpireTime());
    }

    /**
     * 刷新栏目首页推荐问答
     * 10条
     * @param pathId
     */
    public void refreshCTCHomeQuestionList(Long pathId) {
        int maxSize = 12;
        List<CTCHomeRecommendQuestionVO> homeRecommendQuestions = new ArrayList<>();
        List<Long> existQuestionIds = new ArrayList<>(maxSize);
        // 兜底，避免sql报错
        existQuestionIds.add(-1L);
        /**
         * 1、优先2条置顶
         */
        List<CCQuestionEntity> topQuestions = questionDAO.findHomeRecommendTopQuestion(pathId, 2);
        if (CollectionUtils.isNotEmpty(topQuestions)) {
            for (CCQuestionEntity question : topQuestions) {
                homeRecommendQuestions.add(new CTCHomeRecommendQuestionVO(question, QuestionRecommendReasonEnum.TOP.name()));
                existQuestionIds.add(question.getId());
            }
        }
        /**
         * 2、两条推荐
         */
        List<CCQuestionEntity> recommendQuestions = questionDAO.findHomeRecommendRecommendQuestion(pathId, existQuestionIds, 2);
        if (CollectionUtils.isNotEmpty(recommendQuestions)) {
            for (CCQuestionEntity question : recommendQuestions) {
                homeRecommendQuestions.add(new CTCHomeRecommendQuestionVO(question, QuestionRecommendReasonEnum.RECOMMEND.name()));
                existQuestionIds.add(question.getId());
            }
        }
        /**
         * 3、两条悬赏
         */
        List<CCQuestionEntity> rewardQuestions = questionDAO.findHomeRecommendRewardQuestion(pathId, existQuestionIds, 2);
        if (CollectionUtils.isNotEmpty(rewardQuestions)) {
            for (CCQuestionEntity question : rewardQuestions) {
                homeRecommendQuestions.add(new CTCHomeRecommendQuestionVO(question, QuestionRecommendReasonEnum.REWARD.name()));
                existQuestionIds.add(question.getId());
            }
        }
        /**
         * 最新问题补全
         */
        List<CCQuestionEntity> newQuestions = questionDAO.findHomeRecommendNewQuestion(pathId, existQuestionIds, maxSize - existQuestionIds.size() + 1);
        if (CollectionUtils.isNotEmpty(newQuestions)) {
            for (CCQuestionEntity question : newQuestions) {
                homeRecommendQuestions.add(new CTCHomeRecommendQuestionVO(question, QuestionRecommendReasonEnum.NEW.name()));
                existQuestionIds.add(question.getId());
            }
        }
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_QUESTIONS_CACHE.getKey(pathId.toString());
        if (CollectionUtils.isEmpty(homeRecommendQuestions)) {
            redisUtil.remove(key);
            return;
        }
        List<Long> qidList = homeRecommendQuestions.stream().map(CTCHomeRecommendQuestionVO::getId).collect(Collectors.toList());
        Map<Long, Long> viewCountMap = questionService.batchGetQuestionViewCount(qidList);
        Map<Long, Long> answerCountMap = questionService.batchGetQuestionAnswerCountFromCache(qidList);
        for (CTCHomeRecommendQuestionVO questionVO : homeRecommendQuestions) {
            questionVO.setViewCount(viewCountMap.getOrDefault(questionVO.getId(), 0L));
            questionVO.setJoinUserCount(answerCountMap.getOrDefault(questionVO.getId(), 0L));
        }
        redisUtil.set(key, JsonUtil.toJsonString(homeRecommendQuestions), RedisKeyEnum.CTC_HOME_RECOMMEND_QUESTIONS_CACHE.getExpireTime());
    }

    public void refreshCTCHomeVideoList(Long pathId) {
        int maxSize = 50;
        List<CTCHomeRecommendVideoVO> videoBaseVOList = new ArrayList<>();
        /**
         * 2、两条推荐
         */
        List<CCVideoEntity> recommendVideos = videoDAO.findHomeRecommendRecommendVideo(pathId, maxSize);
        if (CollectionUtils.isNotEmpty(recommendVideos)) {
            for (CCVideoEntity video : recommendVideos) {
                videoBaseVOList.add(new CTCHomeRecommendVideoVO(video));
            }
        }
        String key = RedisKeyEnum.CTC_HOME_RECOMMEND_VIDEOS_CACHE.getKey(pathId.toString());
        if (CollectionUtils.isEmpty(videoBaseVOList)) {
            redisUtil.remove(key);
            return;
        }
        List<Long> qidList = videoBaseVOList.stream().map(CTCHomeRecommendVideoVO::getId).collect(Collectors.toList());
        Map<Long, Long> viewCountMap = videoService.batchGetQuestionViewCount(qidList);
        for (CTCHomeRecommendVideoVO videoBaseVO : videoBaseVOList) {
            videoBaseVO.setViewCount(viewCountMap.getOrDefault(videoBaseVO.getId(), 0L));
        }
        redisUtil.set(key, JsonUtil.toJsonString(videoBaseVOList), RedisKeyEnum.CTC_HOME_RECOMMEND_VIDEOS_CACHE.getExpireTime());
    }
}
